package org.light4admin.common;

import lombok.extern.slf4j.Slf4j;
import org.light4admin.common.base.BusinessException;
import org.light4admin.common.base.Response;
import org.light4admin.common.base.ResponseCode;
import org.slf4j.MDC;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author light4admin
 * @date 2018-11-23
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理所有不可知的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public FailedResponse handleException(HttpServletRequest request, Exception e) {
        // 打印堆栈信息
        log.error("异常", e);
        String message = ResponseCode.SYS_EXCEPTION.getMessage();
        return new FailedResponse(ResponseCode.SYS_EXCEPTION.getCode(), transMessage(message));
    }

    /**
     * 处理 ServerException
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    public FailedResponse businessException(HttpServletRequest request, BusinessException e) {
        // 打印堆栈信息
        return new FailedResponse(e.getCode(), transMessage(e.getErrorMessage()));
    }


    @ExceptionHandler(MethodArgumentNotValidException.class)
    public FailedResponse handleMethodArgumentNotValidException(HttpServletRequest request
            , MethodArgumentNotValidException e) {
        // 打印堆栈信息
        String message = getErrorMessage(e);
        return new FailedResponse(ResponseCode.PARAM_ILLEGAL.getCode(), message);
    }

    /**
     * 处理 参数异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    public FailedResponse illegalArgumentException(IllegalArgumentException e) {
        log.warn(e.getMessage());
        return new FailedResponse(ResponseCode.PARAM_ILLEGAL.getCode(), transMessage(e.getMessage()));
    }

    private String transMessage(String message) {
        return message;
    }

    private String getErrorMessage(MethodArgumentNotValidException e) {
        List<FieldError> allErrors = e.getBindingResult().getFieldErrors();
        return String.join(",", allErrors.stream().map(fieldError ->
                fieldError.getField() + ":" + fieldError.getDefaultMessage())
                .collect(Collectors.toList()));
    }

    public static class FailedResponse extends Response<Void> {
        private String errCode;

        public FailedResponse(String message) {
            super(ResponseCode.FAILED.getCode(), message, null);
            this.errCode = MDC.get(Constants.TRACE_ID);
        }

        public FailedResponse(Integer code, String message) {
            super(code, message, null);
            this.errCode = MDC.get(Constants.TRACE_ID);
        }


        public String getErrCode() {
            return errCode;
        }

        public void setErrCode(String errCode) {
            this.errCode = errCode;
        }
    }
}
